﻿/****************************** Module Header ******************************\
 * Module Name:  Hotkey.cs
 * Module Version:  1.0.0 (2013-7-9)
 * Copyright (c) AnyEB.Com (14507247@qq.com)
 * 
 * This class is used to operate the file or the directory. It supplies some
 * public method to move a folder,copy a folder,replace a file and so on.
 * 
 * This source is subject to the GPL License.
 * See http://www.gnu.org/licenses/gpl.html.
 * All other rights reserved.
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace UCL.Forms.WinAPI
{
    /// <summary>
    /// 热键管理类(2013-7-9 by sutroon)
    /// <para>注册热键Shift+S，Id号为100。HotKey.KeyModifiers.Shift也可以直接使用数字4来表示。</para>
    /// <para>HotKey.RegisterHotKey(Handle, 100, HotKey.KeyModifiers.Shift, Keys.S); </para> 
    /// <para>注册热键Ctrl+B，Id号为101。HotKey.KeyModifiers.Ctrl也可以直接使用数字2来表示。</para>
    /// <para>HotKey.RegisterHotKey(Handle, 101, HotKey.KeyModifiers.Ctrl, Keys.B);  </para>
    /// <para>注册热键Ctrl+Alt+D，Id号为102。HotKey.KeyModifiers.Alt也可以直接使用数字1来表示。</para>
    /// <para>HotKey.RegisterHotKey(Handle, 102, HotKey.KeyModifiers.Alt | HotKey.KeyModifiers.Ctrl, Keys.D);</para>  
    /// <para>注册热键F5，Id号为103。  </para>
    /// <para>HotKey.RegisterHotKey(Handle, 103, HotKey.KeyModifiers.None, Keys.F5); </para>
    /// </summary>
    /// <example>
    /// 需要重写Form的WndProc方法
    /// <code>
    /// protected override void WndProc(ref Message m)  
    /// {  
    ///     const int WM_HOTKEY = 0x0312;  
    ///     //按快捷键   
    ///     switch (m.Msg)  
    ///     {  
    ///         case WM_HOTKEY:  
    ///             switch (m.WParam.ToInt32())  
    ///             {  
    ///                 case 100:    //按下的是Shift+S  
    ///                     this.Text = "按下的是Shift+S";  
    ///                     break;  
    ///                 case 101:    //按下的是Ctrl+B  
    ///                     //此处填写快捷键响应代码  
    ///                     this.Text = "按下的是Ctrl+B";  
    ///                     break;  
    ///                 case 102:    //按下的是Alt+D  
    ///                     //此处填写快捷键响应代码  
    ///                     this.Text = "按下的是Ctrl+Alt+D";  
    ///                     break;  
    ///                 case 103:  
    ///                     this.Text = "F5";  
    ///                     break;  
    ///             }  
    ///             break;  
    ///     }  
    ///     base.WndProc(ref m);  
    /// }
    /// </code>
    /// </example>
    public static class HotkeyHelper
    {
        const int WM_HOTKEY = 0x312;
        static int keyid = 10;
        static Dictionary<int, HotKeyCallBackHanlder> keymap = new Dictionary<int, HotKeyCallBackHanlder>();

        public delegate void HotKeyCallBackHanlder();

        #region 系统api
        /// <summary>
        /// 注册快捷键
        /// 如果函数执行成功，返回值不为0。  
        /// 如果函数执行失败，返回值为0。要得到扩展错误信息，调用GetLastError。  
        /// </summary>
        /// <param name="hWnd">要定义热键的窗口的句柄</param>
        /// <param name="id">定义热键ID（不能与其它ID重复）  </param>
        /// <param name="fsModifiers">标识热键是否在按Alt、Ctrl、Shift、Windows等键时才会生效(uint)</param>
        /// <param name="vk">定义热键的内容</param>
        /// <returns></returns>
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);

        /// <summary>
        /// 注销快捷键
        /// </summary>
        /// <param name="hWnd">要取消热键的窗口的句柄</param>
        /// <param name="id">要取消热键的ID</param>
        /// <returns></returns>
        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        #endregion

        /// <summary> 
        /// 注册快捷键 
        /// </summary> 
        /// <param name="hWnd">持有快捷键窗口的句柄</param> 
        /// <param name="fsModifiers">组合键</param> 
        /// <param name="vk">快捷键的虚拟键码</param> 
        /// <param name="callBack">回调函数</param> 
        public static void Regist(IntPtr hWnd, KeyModifiers fsModifiers, Keys vk, HotKeyCallBackHanlder callBack)
        {
            int id = keyid++;
            if (!RegisterHotKey(hWnd, id, fsModifiers, vk))
                throw new Exception("regist hotkey fail.");
            keymap[id] = callBack;
        }

        /// <summary> 
        /// 注销快捷键 
        /// </summary> 
        /// <param name="hWnd">持有快捷键窗口的句柄</param> 
        /// <param name="callBack">回调函数</param> 
        public static void UnRegist(IntPtr hWnd, HotKeyCallBackHanlder callBack)
        {
            foreach (KeyValuePair<int, HotKeyCallBackHanlder> var in keymap)
            {
                if (var.Value == callBack) UnregisterHotKey(hWnd, var.Key);
            }
        }

        /// <summary> 
        /// 快捷键消息处理 
        /// </summary> 
        public static void ProcessHotKey(System.Windows.Forms.Message m)
        {
            if (m.Msg == WM_HOTKEY)
            {
                int id = m.WParam.ToInt32();
                HotKeyCallBackHanlder callback;
                if (keymap.TryGetValue(id, out callback))
                {
                    callback();
                }
            }
        }

        /// <summary>
        /// 定义了辅助键的名称（将数字转变为字符以便于记忆，也可去除此枚举而直接使用数值）
        /// </summary>
        [Flags()]
        public enum KeyModifiers
        {
            None = 0,
            Alt = 0x1,
            Ctrl = 0x2,
            Shift = 0x4,
            Win = 0x8
        }
    }
}
